Security T1330839 - DevExtreme(devextreme-dist@26.1.3) - Potential Prototype Pollution (CWE-1321)#34091
Security T1330839 - DevExtreme(devextreme-dist@26.1.3) - Potential Prototype Pollution (CWE-1321)#34091dmlvr wants to merge 10 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens core/utils/data path-based getters/setters against prototype pollution by detecting unsafe path fragments (__proto__, constructor, prototype) and logging a new error code when such fragments are encountered.
Changes:
- Added unsafe path-fragment detection to
compileGetter,compileSetter, andcombineGettersto prevent prototype pollution vectors. - Introduced a new error code/message
E0123for logging prototype pollution attempts. - Added QUnit tests validating that unsafe fragments are detected/logged and that safe paths still behave normally.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| packages/devextreme/testing/tests/DevExpress.core/utils.data.tests.js | Adds QUnit coverage for prototype-pollution protection behavior in getters/setters |
| packages/devextreme/js/__internal/core/utils/m_data.ts | Implements unsafe fragment detection and logging in path-based getter/setter utilities |
| packages/devextreme/js/__internal/core/m_errors.ts | Adds new error message E0123 for unsafe path fragment detection |
| assert.deepEqual(result, { safe: 'value' }, 'safe field must still be returned'); | ||
| }); | ||
| }); | ||
|
|
There was a problem hiding this comment.
test('compileSetter blocks unsafe fragment written in bracket notation (T1330839)', function(assert) {
const obj = {};
SETTER('a[constructor][prototype].pp_dx')(obj, 'yes', { functionsAsIs: true });
assert.strictEqual(errors.log.calledWith('E0123', 'constructor'), true, 'should log E0123 for constructor in bracket notation');
assert.strictEqual(({}).pp_dx, undefined, 'Object.prototype must not be polluted');
});
test('compileSetter blocks unsafe fragment in non-first position (T1330839)', function(assert) {
const obj = { a: { b: {} } };
SETTER('a.b.__proto__')(obj, { pp_dx: 'yes' }, { functionsAsIs: true });
assert.strictEqual(errors.log.calledWith('E0123', '__proto__'), true, 'should log E0123 for __proto__ in non-first position');
assert.strictEqual(obj.a.b.pp_dx, undefined, 'nested object must not inherit a polluted property');
assert.strictEqual(({}).pp_dx, undefined, 'Object.prototype must not be polluted');
});
|
|
||
| E0122: 'AIIntegration: The sendRequest method is missing.', | ||
|
|
||
| E0123: 'Prototype pollution attempt detected: the path contains an unsafe fragment \'{0}\'', |
There was a problem hiding this comment.
Please verify that your error appears on the documentation page (the technical writers' ticket/card will remain in place) and coordinate this with them.
| const unsafeFragment = path.find(isUnsafePathFragment); | ||
|
|
||
| return function (obj, options) { | ||
| if (unsafeFragment !== undefined) { |
There was a problem hiding this comment.
Let's move the check into compileGetter at the compilation stage. Now it returns a separate no-op function for an unsafe path, as already done in compileSetter.
The getter hot path no longer carries a per-call check, and both functions will be symmetrical.
See comment below
There was a problem hiding this comment.
updated both functions
| errors.log('E0123', unsafeFragment); | ||
| return; | ||
| } | ||
|
|
There was a problem hiding this comment.
- return function (obj, options) {
-
if (unsafeFragment !== undefined) {
- if (unsafeFragment !== undefined) {
-
return function () { errors.log('E0123', unsafeFragment);
-
return; -
}
-
}; -
}
-
return function (obj, options) {
No description provided.